home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xwall / xwalld.c < prev    next >
C/C++ Source or Header  |  1995-06-20  |  16KB  |  580 lines

  1. /*
  2.  * Copyright 1990 University of Wisconsin-Madison
  3.  *
  4.  * Permission to use, copy, modify, distribute, and sell this software and its
  5.  * documentation for any purpose is hereby granted without fee, provided that
  6.  * the above copyright notice appear in all copies and that both that
  7.  * copyright notice and this permission notice appear in supporting
  8.  * documentation, and that the name of the University of Wisconsin-Madison not
  9.  * be used in advertising or publicity pertaining to distribution of the
  10.  * software without specific, written prior permission.  The University of
  11.  * Wisconsin-Madison makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without express or
  13.  * implied warranty.
  14.  *
  15.  * THE UNIVERSITY OF WISCONSIN-MADISON DISCLAIMS ALL WARRANTIES WITH REGARD TO
  16.  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  17.  * FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF WISCONSIN-MADISON BE LIABLE FOR
  18.  * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
  19.  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
  20.  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
  21.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22.  *
  23.  * Author:  Tim Theisen             Department of Computer Sciences
  24.  *          tim@cs.wisc.edu         University of Wisconsin-Madison
  25.  *          uwvax!tim               1210 West Dayton Street
  26.  *          (608)262-0438           Madison, WI   53706
  27.  */
  28.  
  29. #include <stdio.h>
  30. #include <signal.h>
  31. #include <X11/Xos.h>
  32.  
  33. #include <X11/Intrinsic.h>
  34. #include <X11/StringDefs.h>
  35. #include <X11/Shell.h>
  36. #include <X11/Xatom.h>
  37.  
  38. #include <X11/Xaw/AsciiText.h>
  39. #include <X11/Xaw/Cardinals.h>
  40. #include <X11/Xaw/Command.h>
  41. #include <X11/Xaw/Form.h>
  42. #include <X11/Xaw/Label.h>
  43. #include <X11/Xmu/Atoms.h>
  44.  
  45. #include "patchlevel.h"
  46.  
  47. #ifdef SIGNALRETURNSINT
  48. #define SIGVAL int
  49. #else
  50. #define SIGVAL void
  51. #endif
  52.  
  53. /* Respawning is only necessary for X11R4.        */
  54. /* For X11R5, xwalld is run in the Xsetup script. */
  55. #ifndef XlibSpecificationRelease
  56. #define RESPAWN
  57. #endif
  58.  
  59. typedef struct _AppResources {
  60.     int openDelay;
  61.     int pingInterval;
  62.     int pingTimeout;
  63.     Boolean bell, daemon, notify, raise;
  64. } AppResources;
  65.  
  66. AppResources app_resources = {15, 5, 5, True, True, True, True};
  67.  
  68. static XtResource resources[] = {
  69.     {"openDelay", "OpenDelay", XtRInt, sizeof(int),
  70.      XtOffsetOf(AppResources, openDelay), XtRImmediate, (XtPointer)15},
  71.     {"pingInterval", "PingInterval", XtRInt, sizeof(int),
  72.      XtOffsetOf(AppResources, pingInterval), XtRImmediate, (XtPointer)5},
  73.     {"pingTimeout", "PingTimeout", XtRInt, sizeof(int),
  74.      XtOffsetOf(AppResources, pingTimeout), XtRImmediate, (XtPointer)5},
  75.     {"bell", "Bell", XtRBoolean, sizeof(Boolean),
  76.      XtOffsetOf(AppResources, bell), XtRImmediate, (XtPointer)True},
  77.     {"daemon", "Daemon", XtRBoolean, sizeof(Boolean),
  78.      XtOffsetOf(AppResources, daemon), XtRImmediate, (XtPointer)True},
  79.     {"notify", "Notify", XtRBoolean, sizeof(Boolean),
  80.      XtOffsetOf(AppResources, notify), XtRImmediate, (XtPointer)True},
  81.     {"raise", "Raise", XtRBoolean, sizeof(Boolean),
  82.      XtOffsetOf(AppResources, raise), XtRImmediate, (XtPointer)True},
  83. };
  84.  
  85. static XrmOptionDescRec options[] = {
  86.     {"-bell", ".bell", XrmoptionNoArg, (caddr_t)"on"},
  87.     {"-nobell", ".bell", XrmoptionNoArg, (caddr_t)"off"},
  88.     {"-daemon", ".daemon", XrmoptionNoArg, (caddr_t)"on"},
  89.     {"-nodaemon", ".daemon", XrmoptionNoArg, (caddr_t)"off"},
  90.     {"-notify", ".notify", XrmoptionNoArg, (caddr_t)"on"},
  91.     {"-nonotify", ".notify", XrmoptionNoArg, (caddr_t)"off"},
  92.     {"-raise", ".raise", XrmoptionNoArg, (caddr_t)"on"},
  93.     {"-noraise", ".raise", XrmoptionNoArg, (caddr_t)"off"},
  94. };
  95.  
  96. static void Deiconified();
  97. static void Iconified();
  98. static void delete_window();
  99.  
  100. static XtActionsRec actions[] = {
  101.     {"Deiconified",    Deiconified},
  102.     {"Iconified",    Iconified},
  103.     {"Delete",        delete_window},
  104. };
  105.  
  106. String fallback_resources[] = {
  107. #   include "Xwall.ad.h"
  108.     NULL};
  109.  
  110. static void Syntax();
  111. static void make_wall_popup();
  112. extern char *malloc();
  113. static SIGVAL catchALRM();
  114.  
  115. #ifdef RESPAWN
  116. static String *saved_argv;
  117. static int saved_argc;
  118. static SIGVAL catchHUP();
  119. static int catchXError();
  120. static int catchXIOError();
  121. static void catchXtError();
  122. static void respawn();
  123. static int connected;
  124. #endif
  125.  
  126. XtAppContext app_con;
  127. static Display *dpy;
  128. static XtIntervalId timer_id;
  129. static void pingDisplay(); 
  130.  
  131. main(argc, argv)
  132. int argc;
  133. char *argv[];
  134. {
  135.     Widget toplevel;
  136. #ifdef RESPAWN
  137.     int i;
  138.     XErrorHandler oldXError;
  139.     XIOErrorHandler oldXIOError;
  140.  
  141.     saved_argc = argc;
  142.     saved_argv = (String *) malloc((saved_argc + 1) * sizeof(String));
  143.     if (saved_argv == NULL) {
  144.        fprintf(stderr, "%s: Malloc failure!\n, argv[0]");
  145.        exit(1);
  146.     }
  147.     for (i = 0 ; i < saved_argc ; i++) saved_argv[i] = argv[i];
  148.     saved_argv[i] = NULL;    /* NULL terminate that sucker. */
  149.  
  150.     /* make ourselves fairly bullet proof */
  151.     (void) signal(SIGHUP, catchHUP);
  152.     oldXError = XSetErrorHandler (catchXError);
  153.     oldXIOError = XSetIOErrorHandler (catchXIOError);
  154.     XtSetErrorHandler (catchXtError);
  155.  
  156.     /* If we are root, Become daemon right away. */
  157.     /* (Don't want to hold up /etc/rc.) */
  158.     if (getuid() == 0) {
  159.     BecomeOrphan();
  160.     BecomeDaemon();
  161.                     /* If starting from rc wait for */
  162.     sleep(app_resources.openDelay); /* xdm to get the X server ready */
  163.     }
  164.  
  165.     /* Use root Xauthority file. Automatically refreshed upon display reset */
  166.     setuid(0);
  167.     (void) setenv("XAUTHORITY", "/.Xauthority", True);
  168. #endif
  169.  
  170.     XtToolkitInitialize();
  171.     app_con = XtCreateApplicationContext();
  172.     XtAppAddActions(app_con, actions, XtNumber(actions));
  173.     XtAppSetFallbackResources(app_con, fallback_resources);
  174.     (void) signal (SIGALRM, catchALRM);
  175.     (void) alarm (app_resources.pingTimeout*60);
  176.     dpy = XtOpenDisplay(app_con, NULL, NULL, "Xwall",
  177.             options, XtNumber(options), &argc, argv);
  178.     (void) alarm(0);
  179. #ifdef RESPAWN
  180.     if (dpy == NULL) respawn();
  181.     connected = 1;
  182. #else
  183.     if (dpy == NULL) exit(1);
  184. #endif
  185.     toplevel = XtAppCreateShell(NULL, "Xwall", applicationShellWidgetClass,
  186.                 dpy, NULL, ZERO);
  187.  
  188.     if (argc != 1)
  189.     Syntax(argv[0]);
  190.  
  191.     XtGetApplicationResources(toplevel, (XtPointer) &app_resources,
  192.                   resources, XtNumber(resources), NULL, ZERO);
  193.  
  194.     if (app_resources.daemon) {
  195.     BecomeOrphan();
  196.     BecomeDaemon();
  197.     }
  198.  
  199.     /* Ping the display if it is remote */
  200.     if (*DisplayString(dpy) != ':') {
  201.     timer_id = XtAppAddTimeOut(app_con, app_resources.pingInterval*60*1000,
  202.                    pingDisplay, (XtPointer) 0);
  203.     }
  204.     make_wall_popup(toplevel);
  205.     XtAppMainLoop(app_con);
  206. }
  207.  
  208. static void
  209. Syntax(call)
  210. char *call;
  211. {
  212.     XtDestroyApplicationContext(app_con);
  213.     fprintf(stderr, "Usage: %s\n", call);
  214.     fprintf(stderr, "    [-display <display>]\n");
  215.     fprintf(stderr, "    [-[no]bell] [-[no]notify] [-[no]raise]\n");
  216.     exit(1);
  217. }
  218.  
  219. static void
  220. pingDisplay(data, id) 
  221.     XtPointer data;
  222.     XtIntervalId *id;
  223. {
  224.     (void) alarm (app_resources.pingTimeout*60);
  225.     XSync(dpy, 0);
  226.     (void) alarm(0);
  227.     timer_id = XtAppAddTimeOut(app_con, app_resources.pingInterval*60*1000,
  228.                    pingDisplay, (XtPointer) 0);
  229. }
  230.  
  231. #ifdef RESPAWN
  232. static SIGVAL
  233. catchALRM()
  234. {
  235.     respawn();
  236. }
  237. static SIGVAL
  238. catchHUP()
  239. {
  240.     respawn();
  241. }
  242. static int
  243. catchXError(dpy, xev)
  244. Display *dpy;
  245. XErrorEvent *xev;
  246. {
  247.     connected = 1;
  248.     respawn();
  249. }
  250. static int
  251. catchXIOError(dpy)
  252. Display *dpy;
  253. {
  254.     connected = 1;
  255.     respawn();
  256. }
  257. static void
  258. catchXtError(msg)
  259. String msg;
  260. {
  261.     connected = 1;
  262.     respawn();
  263. }
  264. static void
  265. respawn()
  266. {
  267.     if (!connected) /* If we were not connected */
  268.     sleep(app_resources.pingInterval*60);
  269.  
  270.     /* Restart ourself */
  271.     execvp(saved_argv[0], saved_argv);
  272. }
  273. #else
  274. static SIGVAL
  275. catchALRM()
  276. {
  277.     exit(1);
  278. }
  279. #endif
  280.  
  281. #define LINES 10
  282.  
  283. static Time GetTime();
  284. static void LoseSelection();
  285. static Boolean RefuseSelection();
  286. static void LoseManager();
  287. static void InsertMessage();
  288. static void dismiss();
  289. static void Notify();
  290.  
  291. static Atom message, manager;
  292. static Atom wm_delete_window;    /* Atom sent to destroy a window */
  293. static Boolean notified;
  294. static Boolean iconified;
  295. static Widget wall, form, title, text, button;
  296. static int message_length;
  297. static XawTextBlock message_block;
  298.  
  299. static void
  300. make_wall_popup(parent)
  301. Widget parent;
  302. {
  303.     XFontStruct *font;
  304.     Dimension bottomMargin, leftMargin, rightMargin, topMargin;
  305.     Dimension width, height;
  306.     Arg args[9];
  307.  
  308.     wm_delete_window = XInternAtom(XtDisplay(parent), "WM_DELETE_WINDOW",
  309.                    False);
  310.     wall = XtCreatePopupShell("wall", topLevelShellWidgetClass,
  311.                   parent, NULL, ZERO);
  312.     form = XtCreateManagedWidget("form", formWidgetClass,
  313.                  wall, NULL, ZERO);
  314.     XtSetArg(args[0], XtNfromVert, NULL);
  315.     XtSetArg(args[1], XtNresize, False);
  316.     XtSetArg(args[2], XtNborderWidth, 0);
  317.     XtSetArg(args[3], XtNtop, XtChainTop);
  318.     XtSetArg(args[4], XtNbottom, XtChainTop);
  319.     XtSetArg(args[5], XtNleft, XtChainLeft);
  320.     XtSetArg(args[6], XtNright, XtChainRight);
  321.     title = XtCreateManagedWidget("title", labelWidgetClass,
  322.                   form, args, SEVEN);
  323.     XtSetArg(args[0], XtNfromVert, title);
  324.     XtSetArg(args[1], XtNscrollHorizontal, XawtextScrollWhenNeeded);
  325.     XtSetArg(args[2], XtNscrollVertical, XawtextScrollWhenNeeded);
  326.     XtSetArg(args[3], XtNdisplayCaret, False);
  327.     XtSetArg(args[4], XtNdisplayNonprinting, False);
  328.     XtSetArg(args[5], XtNtop, XtChainTop);
  329.     XtSetArg(args[6], XtNbottom, XtChainBottom);
  330.     XtSetArg(args[7], XtNleft, XtChainLeft);
  331.     XtSetArg(args[8], XtNright, XtChainRight);
  332.     text = XtCreateManagedWidget("message", asciiTextWidgetClass,
  333.                  form, args, NINE);
  334.     XtSetArg(args[0], XtNfromVert, text);
  335.     XtSetArg(args[1], XtNresize, False);
  336.     XtSetArg(args[2], XtNtop, XtChainBottom);
  337.     XtSetArg(args[3], XtNbottom, XtChainBottom);
  338.     XtSetArg(args[4], XtNleft, XtChainLeft);
  339.     XtSetArg(args[5], XtNright, XtChainRight);
  340.     button = XtCreateManagedWidget("button", commandWidgetClass,
  341.                    form, args, SIX);
  342.     XtAddCallback(button, XtNcallback, dismiss, NULL);
  343.  
  344.     XtInstallAccelerators(wall, button);
  345.  
  346.     XtSetArg(args[0], XtNfont, &font);
  347.     XtSetArg(args[1], XtNbottomMargin, &bottomMargin);
  348.     XtSetArg(args[2], XtNleftMargin, &leftMargin);
  349.     XtSetArg(args[3], XtNrightMargin, &rightMargin);
  350.     XtSetArg(args[4], XtNtopMargin, &topMargin);
  351.     XtGetValues(text, args, FIVE);
  352.  
  353.     width = font->max_bounds.width * 80 + leftMargin + rightMargin;
  354.     height = (font->ascent + font->descent) * LINES + topMargin + bottomMargin;
  355.  
  356.     XtSetArg(args[0], XtNwidth, width);
  357.     XtSetArg(args[1], XtNheight, height);
  358.     XtSetValues(title, args, ONE);
  359.     XtSetValues(text, args, TWO);
  360.     XtSetValues(button, args, ONE);
  361.  
  362.     XtRealizeWidget(wall);
  363.     XSetWMProtocols(XtDisplay(wall), XtWindow(wall), &wm_delete_window, 1);
  364.  
  365.     manager = XInternAtom(XtDisplay(text), "MESSAGE_MANAGER", False);
  366.     while (!XtOwnSelection(text, manager, GetTime(wall),
  367.                RefuseSelection, LoseManager, NULL)) {}
  368.     message = XInternAtom(XtDisplay(text), "MESSAGE", False);
  369.     while (!XtOwnSelection(text, message, GetTime(wall),
  370.                RefuseSelection, LoseSelection, NULL)) {}
  371. }
  372.  
  373. static Time
  374. GetTime(w)
  375. Widget w;
  376. {
  377.     XSetWindowAttributes attributes;
  378.     static Window myw;
  379.     Time now = 0;
  380.     XEvent event;
  381.     Display *dpy = XtDisplay(w);
  382.  
  383.     /* Create an unmapped window, that the window manager will ignore.
  384.      * This invisble window will be used to do a zero lenght property
  385.      * append.  The event returned furnishes the timestamp */
  386.  
  387.     if (!myw) {
  388.     attributes.override_redirect = True;
  389.     attributes.event_mask = PropertyChangeMask;
  390.     myw = XCreateWindow(dpy, DefaultRootWindow(dpy), 0, 0, 1, 1, 0,
  391.                 CopyFromParent, CopyFromParent, CopyFromParent,
  392.                 CWOverrideRedirect|CWEventMask, &attributes);
  393.     }
  394.  
  395.     XChangeProperty(dpy, myw, XA_NULL(dpy), XA_NULL(dpy), 8,
  396.             PropModeAppend, NULL, 0);
  397.  
  398.     while (now == 0) {
  399.     XtAppNextEvent(app_con, &event);
  400.     if ((event.type == PropertyNotify) && (event.xproperty.window == myw) &&
  401.         (event.xproperty.atom == XA_NULL(dpy)))
  402.         now = event.xproperty.time;
  403.     else
  404.         XtDispatchEvent(&event);
  405.     }
  406.  
  407.     return(now);
  408. }
  409.  
  410. static void
  411. LoseSelection(w, selection)
  412. Widget w;
  413. Atom *selection;
  414. {
  415.     XtGetSelectionValue(w, *selection, XA_STRING, InsertMessage,
  416.             NULL, GetTime(w));
  417. }
  418.  
  419. /*ARGSUSED*/
  420. static Boolean
  421. RefuseSelection(w, selection, target, type, value, length, format)
  422. Widget w;
  423. Atom *selection, *target, *type;
  424. XtPointer *value;
  425. unsigned long *length;
  426. int *format;
  427. {
  428.     return False;
  429. }
  430.  
  431. /*ARGSUSED*/
  432. static void
  433. LoseManager(w, selection)
  434. Widget w;
  435. Atom *selection;
  436. {
  437.     XtDestroyApplicationContext(app_con);
  438.     exit(0);
  439. }
  440.  
  441. static void 
  442. InsertMessage(w, client_data, selection, type, value, length, format)
  443. Widget w;
  444. XtPointer client_data;
  445. Atom *selection, *type;
  446. XtPointer value;
  447. unsigned long *length;
  448. int *format;
  449. {
  450.     Arg args[2];
  451.  
  452.     if (*type == 0 /*XT_CONVERT_FAIL*/ || *length == 0) {
  453.     while (!XtOwnSelection(w, message, GetTime(w),
  454.                    RefuseSelection, LoseSelection, NULL)) {}
  455.     return;
  456.     }
  457.  
  458.     message_block.firstPos = 0;
  459.     message_block.length = *length;
  460.     message_block.ptr = value;
  461.     message_block.format = FMT8BIT;
  462.  
  463.     XawTextDisableRedisplay(text);
  464.  
  465.     XtSetArg(args[0], XtNeditType, XawtextAppend);
  466.     XtSetValues(text, args, ONE);
  467.     XawTextReplace(text, message_length, message_length, &message_block);
  468.     message_length = message_length + message_block.length;
  469.  
  470.     XtSetArg(args[0], XtNeditType, XawtextRead);
  471.     XtSetArg(args[1], XtNinsertPosition, message_length);
  472.     XtSetValues(text, args, TWO);
  473.     XawTextEnableRedisplay(text);
  474.     XtPopup(wall, XtGrabNone);
  475.     if (app_resources.raise) XMapRaised(XtDisplay(wall), XtWindow(wall));
  476.     if (app_resources.bell) XBell(XtDisplay(wall), 0);
  477.     if (app_resources.notify) Notify();
  478.     
  479.     while (!XtOwnSelection(w, message, GetTime(w),
  480.                   RefuseSelection, LoseSelection, NULL)) {}
  481.  
  482.     XtFree(value);
  483. }
  484.  
  485. static void
  486. dismiss(w, client_data, call_data)
  487. Widget w;
  488. XtPointer call_data, client_data;
  489. {
  490.     Arg args[2];
  491.  
  492.     XtPopdown(wall);
  493.     XtSetArg(args[0], XtNeditType, XawtextEdit);
  494.     XtSetArg(args[1], XtNinsertPosition, 0);
  495.     XtSetValues(text, args, TWO);
  496.     message_block.length = 0;
  497.     XawTextReplace(text, 0, message_length, &message_block);
  498.     XtSetArg(args[0], XtNeditType, XawtextRead);
  499.     XtSetValues(text, args, ONE);
  500.     message_length = 0;
  501.  
  502. }
  503.  
  504. /* Implement WM_DELETE_WINDOW protocol */
  505. static void
  506. delete_window(w, event, params, num_params)
  507.     Widget w;
  508.     XEvent *event;
  509.     String *params;
  510.     Cardinal *num_params;
  511. {
  512.     if (event->type == ClientMessage &&
  513.         event->xclient.data.l[0] != wm_delete_window) return;
  514.     dismiss(w, (XtPointer)NULL, (XtPointer)NULL);
  515. }
  516.  
  517. static void
  518. Notify ()
  519. {
  520.     Arg        arglist[1];
  521.     char    *oldName;
  522.     char    *newName;
  523.  
  524.     if (!iconified || !app_resources.notify || notified)
  525.     return;
  526.     XtSetArg (arglist[0], XtNiconName, &oldName);
  527.     XtGetValues (wall, arglist, 1);
  528.     newName = malloc (strlen (oldName) + 3);
  529.     if (!newName)
  530.     return;
  531.     sprintf (newName, "%s *", oldName);
  532.     XtSetArg (arglist[0], XtNiconName, newName);
  533.     XtSetValues (wall, arglist, 1);
  534.     free (newName);
  535.     notified = True;
  536. }
  537.  
  538. /*ARGSUSED*/
  539. static void
  540. Deiconified (widget, event, params, num_params)
  541.     Widget widget;
  542.     XEvent *event;
  543.     String *params;
  544.     Cardinal *num_params;
  545. {
  546.     Arg        arglist[1];
  547.     char    *oldName;
  548.     char    *newName;
  549.     int        oldlen;
  550.  
  551.     iconified = False;
  552.     if (!app_resources.notify || !notified)
  553.     return;
  554.     XtSetArg (arglist[0], XtNiconName, &oldName);
  555.     XtGetValues (wall, arglist, 1);
  556.     oldlen = strlen (oldName);
  557.     if (oldlen >= 2) {
  558.         newName = malloc (oldlen - 1);
  559.         if (!newName)
  560.         return;
  561.         strncpy (newName, oldName, oldlen - 2);
  562.     newName[oldlen - 2] = '\0';
  563.         XtSetArg (arglist[0], XtNiconName, newName);
  564.         XtSetValues (wall, arglist, 1);
  565.         free (newName);
  566.     }
  567.     notified = False;
  568. }
  569.  
  570. /*ARGSUSED*/
  571. static void
  572. Iconified (widget, event, params, num_params)
  573.     Widget widget;
  574.     XEvent *event;
  575.     String *params;
  576.     Cardinal *num_params;
  577. {
  578.     iconified = True;
  579. }
  580.